package com.cxb.springboot.service;

/**
 * @Classname CuratorLockService
 * @Description TODO
 * @Date 2023/3/28 22:41
 * @Created by Administrator
 */

import com.cxb.springboot.common.AbstractLock;
import com.cxb.springboot.common.ZookeeperClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class CuratorLockService {

    @Autowired
    private ZookeeperClient zookeeperClient;

    @Autowired
    private CuratorFramework curatorFramework;

    //库存存取的路径
    private static final String dataPath = "/root/data/stock";

    /**
     * 此方法系统启动执行，使用zookeeper存一个库存用于测试，这里也使用了锁。（只是一个模拟初始化库存的方法）
     */
    @PostConstruct
    public void init() {
        zookeeperClient.lock(new AbstractLock<Boolean>(dataPath, 20, TimeUnit.SECONDS) {
            @Override
            public Boolean execute() {
                try {
                    //判断是否存在路径
                    Stat stat = curatorFramework.checkExists().forPath(dataPath);
                    if (stat == null) {
                        //为空则不存在，则创建并设置库存值
                        curatorFramework.create().creatingParentContainersIfNeeded().forPath(dataPath, "1000".getBytes());
                        log.info("初始化数据完成");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
                return true;
            }
        });
    }

    public String inventoryDeduct(String lockId) {
        //我这里是演示，实际对于不同的业务锁路径设置不同，比如支付和订单设置为"/root/pay/"和"/root/order/"
        String lockPath = "/root/frank/" + lockId;
        //调用加锁方法
        Integer result = zookeeperClient.lock(new AbstractLock<Integer>(lockPath, 10, TimeUnit.SECONDS) {
            @Override
            public Integer execute() {
                try {
                    //模拟业务处理
                    byte[] bytes = curatorFramework.getData().forPath(dataPath);
                    String data = new String(bytes);
                    int stock = Integer.parseInt(data);
                    if (stock > 0) {
                        //扣减库存
                        stock--;
                        curatorFramework.setData().forPath(dataPath, (stock + "").getBytes());
                    }
                    return stock;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
        if (result == null) {
            log.info("业务执行失败");
            return "业务执行失败";
        } else {
            log.info("执行成功,剩余库存：" + result);
            return "执行成功,剩余库存：" + result;
        }
    }

    /**
     * 获取分布式ID
     * @param path
     * @param data
     * @return
     * @throws Exception
     */
    public String getDistributedId(String path, String data) throws Exception {
        String seqNode = this.createTypeSeqNode(CreateMode.EPHEMERAL_SEQUENTIAL, path, data);
        System.out.println(seqNode);
        int index = seqNode.lastIndexOf(path);
        if (index >= 0) {
            index += path.length();
            return index <= seqNode.length() ? seqNode.substring(index) : "";
        }
        return seqNode;
    }

    /**
     * 创建指定类型的有序节点
     * @param nodeType
     * @param path
     * @param data
     * @return
     */
    public String createTypeSeqNode(CreateMode nodeType, String path, String data) throws Exception {
        String nodePath = curatorFramework.create().creatingParentsIfNeeded().withProtection().withMode(nodeType)
                .forPath(path, data.getBytes(StandardCharsets.UTF_8));
        return nodePath;
    }


}

